home *** CD-ROM | disk | FTP | other *** search
/ Visual Basic Graphics Programming (2nd Edition) / Visual Basic Graphics Programming 2nd Edition.iso / OldSrc / CH11 / SRC / OBJPLIN2.CLS < prev    next >
Text File  |  1996-05-04  |  13KB  |  486 lines

  1. VERSION 1.0 CLASS
  2. BEGIN
  3.   MultiUse = -1  'True
  4. END
  5. Attribute VB_Name = "ObjPolyline"
  6. Attribute VB_Creatable = False
  7. Attribute VB_Exposed = False
  8. Option Explicit
  9.  
  10. ' Point3D and Segment3D are defined in module M3OPS.BAS as:
  11. '    Type Point3D
  12. '        coord(1 To 4) As Single
  13. '        trans(1 To 4) As Single
  14. '    End Type
  15. '
  16. '    Type Segment3D
  17. '        pt1 As Integer
  18. '        pt2 As Integer
  19. '    End Type
  20.  
  21. Private NumPoints As Integer ' Number of points.
  22. Private Points() As Point3D  ' Data points.
  23.  
  24. Private NumSegs As Integer   ' Number of segments.
  25. Private Segs() As Segment3D  ' The segments.
  26.  
  27. Private IsCulled As Boolean
  28.  
  29. ' ***********************************************
  30. ' This is done at drawing time for polylines.
  31. ' ***********************************************
  32. Public Sub ClipEye(r As Single)
  33. End Sub
  34.  
  35. ' ************************************************
  36. ' Draw the transformed points on a Form, Printer,
  37. ' or PictureBox using API functions.
  38. ' ************************************************
  39. Public Sub DrawOrdered(canvas As Object, Optional r As Variant)
  40. Dim seg As Integer
  41. Dim pt1 As Integer
  42. Dim pt2 As Integer
  43. Dim dist As Single
  44. Dim status As Long
  45.  
  46.     ' Don't draw if culled.
  47.     If IsCulled Then Exit Sub
  48.     
  49.     On Error Resume Next
  50.     If IsMissing(r) Then r = INFINITY
  51.     dist = r
  52.     For seg = 1 To NumSegs
  53.         pt1 = Segs(seg).pt1
  54.         pt2 = Segs(seg).pt2
  55.         ' Don't draw if either point is farther
  56.         ' from the focus point than the center of
  57.         ' projection (which is distance dist away).
  58.         If Points(pt1).trans(3) < dist And _
  59.            Points(pt2).trans(3) < dist Then
  60.                 #If Win32 Then
  61.                     status = API_MoveTo(canvas.hdc, _
  62.                         Points(pt1).trans(1), _
  63.                         Points(pt1).trans(2), 0&)
  64.                 #Else
  65.                     status = API_MoveTo(canvas.hdc, _
  66.                         Points(pt1).trans(1), _
  67.                         Points(pt1).trans(2))
  68.                 #End If
  69.                 status = API_LineTo(canvas.hdc, _
  70.                     Points(pt2).trans(1), _
  71.                     Points(pt2).trans(2))
  72.         End If
  73.     Next seg
  74. End Sub
  75.  
  76. ' ***********************************************
  77. ' Return the maximum transformed Z value for this
  78. ' object.
  79. ' ***********************************************
  80. Property Get zmax() As Single
  81. Dim best As Single
  82. Dim z As Single
  83. Dim i As Integer
  84.  
  85.     best = Points(1).trans(3)
  86.     For i = 2 To NumPoints
  87.         z = Points(i).trans(3)
  88.         If best < z Then best = z
  89.     Next i
  90.     zmax = best
  91. End Property
  92.  
  93.  
  94.  
  95. Sub Stellate(L As Single, ParamArray coord() As Variant)
  96. Dim x0 As Single
  97. Dim y0 As Single
  98. Dim z0 As Single
  99. Dim x1 As Single
  100. Dim y1 As Single
  101. Dim z1 As Single
  102. Dim x2 As Single
  103. Dim y2 As Single
  104. Dim z2 As Single
  105. Dim x3 As Single
  106. Dim y3 As Single
  107. Dim z3 As Single
  108. Dim Ax As Single
  109. Dim Ay As Single
  110. Dim Az As Single
  111. Dim Bx As Single
  112. Dim By As Single
  113. Dim Bz As Single
  114. Dim nx As Single
  115. Dim ny As Single
  116. Dim nz As Single
  117. Dim num As Integer
  118. Dim i As Integer
  119. Dim pt As Integer
  120.  
  121.     num = (UBound(coord) + 1) \ 3
  122.     If num < 3 Then
  123.         Beep
  124.         MsgBox "Must have at least 3 points to stellate.", , vbExclamation
  125.         Exit Sub
  126.     End If
  127.     
  128.     ' (x0, y0, z0) is the center of the polygon.
  129.     x0 = 0
  130.     y0 = 0
  131.     z0 = 0
  132.     pt = 0
  133.     For i = 1 To num
  134.         x0 = x0 + coord(pt)
  135.         y0 = y0 + coord(pt + 1)
  136.         z0 = z0 + coord(pt + 2)
  137.         pt = pt + 3
  138.     Next i
  139.     x0 = x0 / num
  140.     y0 = y0 / num
  141.     z0 = z0 / num
  142.     
  143.     ' Find the normal.
  144.     x1 = coord(0)
  145.     y1 = coord(1)
  146.     z1 = coord(2)
  147.     x2 = coord(3)
  148.     y2 = coord(4)
  149.     z2 = coord(5)
  150.     x3 = coord(6)
  151.     y3 = coord(7)
  152.     z3 = coord(8)
  153.     Ax = x2 - x1
  154.     Ay = y2 - y1
  155.     Az = z2 - z1
  156.     Bx = x3 - x2
  157.     By = y3 - y2
  158.     Bz = z3 - z2
  159.     m3Cross nx, ny, nz, Ax, Ay, Az, Bx, By, Bz
  160.     
  161.     ' Give the normal length L.
  162.     m3SizeVector L, nx, ny, nz
  163.     
  164.     ' The normal + <x0, y0, z0> gives the point.
  165.     x0 = x0 + nx
  166.     y0 = y0 + ny
  167.     z0 = z0 + nz
  168.  
  169.     ' Build the segments that make up the object.
  170.     x1 = coord(3 * num - 3)
  171.     y1 = coord(3 * num - 2)
  172.     z1 = coord(3 * num - 1)
  173.     pt = 0
  174.     For i = 1 To num
  175.         x2 = coord(pt)
  176.         y2 = coord(pt + 1)
  177.         z2 = coord(pt + 2)
  178.         AddSegment x1, y1, z1, x2, y2, z2, x0, y0, z0
  179.         x1 = x2
  180.         y1 = y2
  181.         z1 = z2
  182.         pt = pt + 3
  183.     Next i
  184. End Sub
  185.  
  186. Sub CreateNormal(Objects As Collection)
  187. Dim pline As New ObjPolyline
  188. Dim x1 As Single
  189. Dim y1 As Single
  190. Dim z1 As Single
  191. Dim x2 As Single
  192. Dim y2 As Single
  193. Dim z2 As Single
  194.  
  195.     Objects.Add pline
  196.     UnitNormalSegment x1, y1, z1, x2, y2, z2
  197.     pline.AddSegment x1, y1, z1, x2, y2, z2
  198. End Sub
  199.  
  200.  
  201. ' ***********************************************
  202. ' Compute a normal vector for this polyline.
  203. ' ***********************************************
  204. Sub NormalVector(nx As Single, ny As Single, nz As Single)
  205. Dim Ax As Single
  206. Dim Ay As Single
  207. Dim Az As Single
  208. Dim Bx As Single
  209. Dim By As Single
  210. Dim Bz As Single
  211.  
  212.     Ax = Points(2).coord(1) - Points(1).coord(1)
  213.     Ay = Points(2).coord(2) - Points(1).coord(2)
  214.     Az = Points(2).coord(3) - Points(1).coord(3)
  215.     Bx = Points(3).coord(1) - Points(2).coord(1)
  216.     By = Points(3).coord(2) - Points(2).coord(2)
  217.     Bz = Points(3).coord(3) - Points(2).coord(3)
  218.     m3Cross nx, ny, nz, Ax, Ay, Az, Bx, By, Bz
  219. End Sub
  220.  
  221.  
  222.  
  223. ' ***********************************************
  224. ' Compute the unit normal line segment for this
  225. ' polyline.
  226. ' ***********************************************
  227. Sub UnitNormalSegment(x1 As Single, y1 As Single, z1 As Single, x2 As Single, y2 As Single, z2 As Single)
  228. Dim i As Integer
  229. Dim nx As Single
  230. Dim ny As Single
  231. Dim nz As Single
  232.     
  233.     UnitNormalVector nx, ny, nz
  234.     
  235.     x1 = 0
  236.     y1 = 0
  237.     z1 = 0
  238.     For i = 1 To NumPoints
  239.         x1 = x1 + Points(i).coord(1)
  240.         y1 = y1 + Points(i).coord(2)
  241.         z1 = z1 + Points(i).coord(3)
  242.     Next i
  243.     x1 = x1 / NumPoints
  244.     y1 = y1 / NumPoints
  245.     z1 = z1 / NumPoints
  246.  
  247.     x2 = x1 + nx
  248.     y2 = y1 + ny
  249.     z2 = z1 + nz
  250. End Sub
  251.  
  252.  
  253. ' ***********************************************
  254. ' Compute the unit normal vector for this
  255. ' polyline.
  256. ' ***********************************************
  257. Sub UnitNormalVector(nx As Single, ny As Single, nz As Single)
  258. Dim D As Single
  259.  
  260.     NormalVector nx, ny, nz
  261.     D = Sqr(nx * nx + ny * ny + nz * nz)
  262.     nx = nx / D
  263.     ny = ny / D
  264.     nz = nz / D
  265. End Sub
  266.  
  267.  
  268.  
  269.  
  270.  
  271. Property Let Culled(value As Boolean)
  272.     IsCulled = value
  273. End Property
  274.  
  275.  
  276. ' ***********************************************
  277. ' Return a string indicating the object type.
  278. ' ***********************************************
  279. Property Get ObjectType() As String
  280.     ObjectType = "POLYLINE"
  281. End Property
  282.  
  283. ' ************************************************
  284. ' Add one or more line segments to the polyline.
  285. ' ************************************************
  286. Public Sub AddSegment(ParamArray coord() As Variant)
  287. Dim num_segs As Integer
  288. Dim i As Integer
  289. Dim last As Integer
  290. Dim pt As Integer
  291.  
  292.     num_segs = (UBound(coord) + 1) \ 3 - 1
  293.     ReDim Preserve Segs(1 To NumSegs + num_segs)
  294.  
  295.     last = AddPoint((coord(0)), (coord(1)), (coord(2)))
  296.     pt = 0
  297.     For i = 1 To num_segs
  298.         Segs(NumSegs + i).pt1 = last
  299.         pt = pt + 3
  300.         last = AddPoint((coord(pt)), (coord(pt + 1)), (coord(pt + 2)))
  301.         Segs(NumSegs + i).pt2 = last
  302.     Next i
  303.  
  304.     NumSegs = NumSegs + num_segs
  305. End Sub
  306.  
  307. ' ************************************************
  308. ' Add a point to the polyline. Return the point's
  309. ' index.
  310. ' ************************************************
  311. Private Function AddPoint(x As Single, y As Single, z As Single) As Integer
  312. Dim i As Integer
  313.  
  314.     ' See if the point is already here.
  315.     For i = 1 To NumPoints
  316.         If x = Points(i).coord(1) And _
  317.            y = Points(i).coord(2) And _
  318.            z = Points(i).coord(3) Then _
  319.                 Exit For
  320.     Next i
  321.     AddPoint = i
  322.     
  323.     ' If so, we're done.
  324.     If i <= NumPoints Then Exit Function
  325.     
  326.     ' Otherwise create the new point.
  327.     NumPoints = NumPoints + 1
  328.     ReDim Preserve Points(1 To NumPoints)
  329.     Points(i).coord(1) = x
  330.     Points(i).coord(2) = y
  331.     Points(i).coord(3) = z
  332.     Points(i).coord(4) = 1#
  333. End Function
  334.  
  335.  
  336. ' ***********************************************
  337. ' Fix the data coordinates at their transformed
  338. ' values.
  339. ' ***********************************************
  340. Public Sub FixPoints()
  341. Dim i As Integer
  342. Dim j As Integer
  343.  
  344.     For i = 1 To NumPoints
  345.         For j = 1 To 3
  346.             Points(i).coord(j) = Points(i).trans(j)
  347.         Next j
  348.     Next i
  349. End Sub
  350.  
  351. ' ************************************************
  352. ' Apply a transformation matrix which may not
  353. ' contain 0, 0, 0, 1 in the last column to the
  354. ' object.
  355. ' ************************************************
  356. Public Sub ApplyFull(M() As Single)
  357. Dim i As Integer
  358.  
  359.     If IsCulled Then Exit Sub
  360.     For i = 1 To NumPoints
  361.         m3ApplyFull Points(i).coord, M, Points(i).trans
  362.     Next i
  363. End Sub
  364.  
  365. ' ************************************************
  366. ' Apply a transformation matrix to the object.
  367. ' ************************************************
  368. Public Sub Apply(M() As Single)
  369. Dim i As Integer
  370.  
  371.     If IsCulled Then Exit Sub
  372.     For i = 1 To NumPoints
  373.         m3Apply Points(i).coord, M, Points(i).trans
  374.     Next i
  375. End Sub
  376.  
  377.  
  378. ' ************************************************
  379. ' Apply a nonlinear transformation.
  380. ' ************************************************
  381. Public Sub Distort(D As Object)
  382. Dim i As Integer
  383.  
  384.     For i = 1 To NumPoints
  385.         D.Distort Points(i).coord(1), Points(i).coord(2), Points(i).coord(3)
  386.     Next i
  387. End Sub
  388.  
  389. ' ************************************************
  390. ' Write a polyline to a file using Write.
  391. ' Begin with "POLYLINE" to identify this object.
  392. ' ************************************************
  393. Public Sub FileWrite(filenum As Integer)
  394. Dim i As Integer
  395.  
  396.     Write #filenum, "POLYLINE", NumPoints, NumSegs
  397.     
  398.     ' Write the points.
  399.     For i = 1 To NumPoints
  400.         Write #filenum, Points(i).coord(1), Points(i).coord(2), Points(i).coord(3)
  401.     Next i
  402.  
  403.     ' Write the segments.
  404.     For i = 1 To NumSegs
  405.         Write #filenum, Segs(i).pt1, Segs(i).pt2
  406.     Next i
  407. End Sub
  408.  
  409. ' ************************************************
  410. ' Draw the transformed points on a Form, Printer,
  411. ' or PictureBox.
  412. ' ************************************************
  413. Public Sub Draw(canvas As Object, Optional r As Variant)
  414. Dim seg As Integer
  415. Dim pt1 As Integer
  416. Dim pt2 As Integer
  417. Dim dist As Single
  418.  
  419.     ' Don't draw if culled.
  420.     If IsCulled Then Exit Sub
  421.     
  422.     On Error Resume Next
  423.     If IsMissing(r) Then r = INFINITY
  424.     dist = r
  425.     For seg = 1 To NumSegs
  426.         pt1 = Segs(seg).pt1
  427.         pt2 = Segs(seg).pt2
  428.         ' Don't draw if either point is farther
  429.         ' from the focus point than the center of
  430.         ' projection (which is distance dist away).
  431.         If Points(pt1).trans(3) < dist And _
  432.            Points(pt2).trans(3) < dist Then _
  433.                 canvas.Line _
  434.                     (Points(pt1).trans(1), Points(pt1).trans(2))- _
  435.                     (Points(pt2).trans(1), Points(pt2).trans(2))
  436.     Next seg
  437. End Sub
  438. ' ***********************************************
  439. ' Perform backface removal.
  440. ' ***********************************************
  441. Public Sub Cull(x As Single, y As Single, z As Single)
  442. Dim Ax As Single
  443. Dim Ay As Single
  444. Dim Az As Single
  445. Dim nx As Single
  446. Dim ny As Single
  447. Dim nz As Single
  448.  
  449.     ' Compute a normal to the face.
  450.     NormalVector nx, ny, nz
  451.  
  452.     ' Compute a vector from the center of
  453.     ' projection to the face.
  454.     Ax = Points(1).coord(1) - x
  455.     Ay = Points(1).coord(2) - y
  456.     Az = Points(1).coord(3) - z
  457.     
  458.     ' See if the vectors meet at an angle < 90.
  459.     IsCulled = (Ax * nx + Ay * ny + Az * nz >= 0)
  460. End Sub
  461. ' ************************************************
  462. ' Read a polyline from a file using Input.
  463. ' Assume the "POLYLINE" label has already been
  464. ' read.
  465. ' ************************************************
  466. Public Sub FileInput(filenum As Integer)
  467. Dim i As Integer
  468.  
  469.     Input #filenum, NumPoints, NumSegs
  470.     
  471.     ' Allocate and read the points.
  472.     ReDim Points(1 To NumPoints)
  473.     For i = 1 To NumPoints
  474.         Input #filenum, Points(i).coord(1), Points(i).coord(2), Points(i).coord(3)
  475.         Points(i).coord(4) = 1
  476.     Next i
  477.     
  478.     ' Allocate and read the segments.
  479.     ReDim Segs(1 To NumSegs)
  480.     For i = 1 To NumSegs
  481.         Input #filenum, Segs(i).pt1, Segs(i).pt2
  482.     Next i
  483. End Sub
  484.  
  485.  
  486.